/**
 * 引用 signalr 库, 环境不需要则注释下面这行
 * for nodejs: import * as signalR from "@microsoft/signalr";
 */

/**
 * message type enum
 * for nodejs: export const MessageType = { //... }
 */
const MessageType = {
    /**
     * Text message
     */
    Text: "Text",
    /**
     * Data message
     */
    Data: "Data",
    /**
     * Image message
     */
    Image: "Image",
    /**
     * Video message
     */
    Video: "Video",
    /**
     * Cache refresh message
     */
    Cache: "Cache",
    /**
     * Notice message
     */
    Notice: "Notice",
    /**
     * Warning message
     */
    Warning: "Warning",
    /**
     * Error message
     */
    Error: "Error",
    /**
     * Ack message
     */
    Ack: 'Ack',
    /**
     * Read message
     */
    Read: 'Ack',
    /**
     * Heartbeat message
     */
    Heartbeat: 'Heartbeat',
    /**
     * Other message
     */
    Other: "Other",
};

/**
 * 通讯器参数
 * for nodejs: export const CommunicatorOptions = { //... }
 */
const CommunicatorOptions = {
    /**
     * 调试模式
     */
    debug: false,
    /**
     * 通讯服务器地址
     */
    host: undefined,
    /**
     * 当前用户
     */
    user: "test",
    /**
     * 当前客户端标识
     */
    client: undefined,
    /**
     * 默认的消息接收者
     */
    receiver: "dev",
    /**
     * 监控间隔
     */
    interval: 10000,
    /**
     * 收到服务器消息时的处理方法
     */
    onReceive: (message) => console.log(`communicator user ${this.user} in client ${this.client} received the ${message.type} message "${message.content}" from ${message.receiver} sent at ${message.sendTime}!`),
    /**
     * 收到通知消息时的处理方法
     */
    onNotice: (message) => console.log(`communicator user ${this.user} in client ${this.client} received the Notice message "${message.content}" from ${message.receiver} sent at ${message.sendTime}!`),
    /**
     * 收到警告消息时的处理方法
     */
    onWarning: (message) => console.warn(`communicator user ${this.user} in client ${this.client} received the Warning message "${message.content}" from ${message.receiver} sent at ${message.sendTime}!`),
    /**
     * 收到错误消息时的处理方法
     */
    onError: (message) => console.error(`communicator user ${this.user} in client ${this.client} received the Error message "${message.content}" from ${message.receiver} sent at ${message.sendTime}!`),
    /**
     * 收到消息已读时的处理方法
     */
    onRead: (message) => console.log(`communicator user ${message.sender} in client ${message.from} received the Read message "${message.content}" at ${message.readTime}!`),
    /**
     * 收到消息回执时的处理方法
     */
    onAck: (message) => console.log(`communicator user ${message.sender} in client ${message.from} received the Ack message "${message.content}" at ${message.receiveTime}!`),
};

/**
 * 通讯器
 * 当前模式在初始化时, 将接收一个 CommunicatorOptions 参数对通讯器进行初始化
 * for nodejs: export default class Communicator
 */
class Communicator {
    constructor(options) {
        this.options = Object.assign({}, CommunicatorOptions, options);
        if (this.options.user) {
            this.options.url = this.options.host + "?user=" + this.options.user;
            if (this.options.client) {
                this.options.url += "&client=" + this.options.client;
            }
            if (this.options.receiver) {
                this.options.url += "&receiver=" + this.options.receiver;
            }

            this.connection = new signalR.HubConnectionBuilder()
                .withUrl(this.options.url, {
                    skipNegotiation: true,
                    transport: signalR.HttpTransportType.WebSockets,
                })
                .build();

            this.connection.onclose(() => this.connect());
        }
    }

    /**
     * 启动连接
     */
    start() {
        this.connect();

        //启动断线重连检查
        setTimeout(() => this.connect(), this.options.interval);
    }

    /**
     * 连接到服务器
     */
    connect() {
        try {
            if (this.connection.state == signalR.HubConnectionState.Disconnected) {
                this.connection
                    .start()
                    .then(() => {
                        if (this.options.debug) {
                            console.log(`communicator user ${this.options.user} in client ${this.options.client} has been connected to ${this.options.host} !`);
                        }

                        //启动后注册方法
                        this.onAck();
                        this.onRead();
                        this.onReceive();
                    })
                    .catch((err) => {
                        if (this.options.debug) {
                            console.error(err);
                        }
                    });
            }
        } catch (err) {
            if (this.options.debug) {
                console.error(err);
            }
        }
    }

    /**
     * 调用服务器 Send 方法, 发送内容给给服务器
     * @param {string} content 发送的内容
     * @param {string} messageType 消息类型, 默认 文本消息
     * @param {string} receiver 
     * @param {string} id 消息编号  
     */
    async send(content, messageType, receiver, id) {
        var message = {
            id: id,
            sender: this.options.user,
            sendTime: new Date(),
            receiver: receiver || this.options.receiver,
            type: messageType || MessageType.Text,
            content: content,
        };

        return await this.connection
            .invoke("Send", message)
            .then(() => {
                if (this.options.debug) {
                    console.log(`communicator user ${this.options.user} in client ${this.options.client} Send the message "${message.content}" to ${this.options.receiver} at ${message.sendTime}!`);
                }

                return message;
            });
    }

    /**
     * 获取在线用户
     */
    async getOnlineUsers() {
        return await this.connection
            .invoke("GetOnlineUsers")
            .catch((err) => {
                if (this.options.debug) {
                    console.error(err);
                }
            });
    }

    /**
     * 通讯器接收消息已读
     */
    onRead() {
        const method = "Read";
        this.connection.off(method);
        this.connection.on(method, this.options.onRead);
    }

    /**
     * 通讯器接收消息回执
     */
    onAck() {
        const method = "Ack";
        this.connection.off(method);
        this.connection.on(method, this.options.onAck);
    }

    /**
     * 注册通讯器接收数据的方法供服务器调用
     */
    onReceive() {
        const method = "Receive";
        this.connection.off(method);
        this.connection.on(method, async (message) => {
            if (message.sender != this.options.user) {
                //自动发送回执
                await this.ack(message);
            }

            switch (message.type) {
                case MessageType.Error:
                    this.options.onError(message);
                    break;
                case MessageType.Warning:
                    this.options.onWarning(message);
                    break;
                case MessageType.Notice:
                    this.options.onNotice(message);
                    break;
                default:
                    this.options.onReceive(message);
                    break;
            }
        });
    }

    /**
     * 发送回执
     */
    async ack(message) {
        await this.connection
            .invoke("Ack", { id: message.id, from: this.options.client })
            .then(() => {
                if (this.options.debug) {
                    console.log(`communicator user ${this.options.user} in client ${this.options.client} send Ack message to ${message.sender}!`);
                }
            })
            .catch((err) => {
                if (this.options.debug) {
                    console.error(err);
                }
            });
    }
}